<script lang="ts" setup>
import { computed, onMounted, ref, shallowRef, watch } from "vue";
import { BuildTaskRecord, BuildTaskResult, WsMsgType } from "../../model";
import { listTaskResultMap } from "../../api/task";
import { echarts } from "../../config/echarts";
import { useTypeListStore } from "../../store/typeListStore";
import { useWs } from "../../utils/ws";
import {
  useDebounceFn,
  useEventListener,
  useResizeObserver,
} from "@vueuse/core";
import {
  defaultOption,
  chartTypeOption,
  timeStatsOption,
  columns,
  TableDataItem,
} from "./index.data";

const props = defineProps<{
  task?: BuildTaskRecord | null;
}>();

const { getTypeName } = useTypeListStore();
const echartRef = ref<HTMLDivElement>();
const chartRef = shallowRef<echarts.ECharts>();
const dialogVisible = ref(false);
const activeType = ref<keyof BuildTaskResult["timeStats"]>("total");
const chartType = ref<"bar" | "line">("bar");
const chartData = shallowRef<Record<string, BuildTaskResult[]>>({});

const normalizeCostNum = (num: number) => {
  if (num === Number.MAX_VALUE) return 0;
  return Number(num.toFixed(1));
};

const dataSource = computed(() => {
  if (!props.task) return [];
  let rslt: TableDataItem[] = [];
  for (let item of props.task.taskList) {
    const list = chartData.value[item.type] || [];
    let avg = 0;
    let max = 0;
    let min = Number.MAX_VALUE;
    // 填充值,并计算平均值
    list.map((v, i) => {
      const num = v.timeStats[activeType.value] || 0;
      avg += num / list.length;
      max = max > num ? max : num;
      min = min < num ? min : num;
    });
    rslt.push({
      name: getTypeName(item.type),
      min: normalizeCostNum(min),
      max: normalizeCostNum(max),
      avg: normalizeCostNum(avg),
      total: item.total,
      rest: item.rest,
    });
  }

  return rslt;
});

const updateChart = (data: Record<string, BuildTaskResult[]>) => {
  if (!props.task) return;
  let series: any[] = [];
  // 计算长的任务
  const maxLen = props.task.taskList
    .map((v) => v.total)
    .reduce((pre, cur) => {
      return Math.max(pre, cur);
    }, 0);
  for (let item of props.task.taskList) {
    const list = data[item.type] || [];
    const totalArr = new Array(item.total).fill(0);
    let avgVal = 0;
    // 填充值,并计算平均值
    list.map((v, i) => {
      const num = v.timeStats[activeType.value] || 0;
      avgVal += num / list.length;
      totalArr[i] = num;
    });
    series.push({
      name: getTypeName(item.type),
      type: chartType.value,
      data: totalArr,
      barMaxWidth: 32,
      markLine: {
        data: [
          // 自定义平均值
          {
            name: "Avg",
            yAxis: normalizeCostNum(avgVal),
            label: {
              formatter: "{b} {c} ms",
            },
          },
        ],
      },
    });
  }

  const option = {
    xAxis: {
      type: "category",
      boundaryGap: chartType.value === "bar",
      data: new Array(maxLen).fill(0).map((_, i) => i + 1),
    },
    series,
  };
  chartRef.value?.setOption(option);
};

const refreshRsltList = () => {
  if (!props.task?.taskId) return;
  listTaskResultMap(props.task?.taskId).then((res) => {
    chartData.value = res;
    updateChart(chartData.value);
  });
};

const switchStatsType = () => {
  updateChart(chartData.value);
};

const switchChartType = () => {
  updateChart(chartData.value);
};

watch(
  () => props.task?.taskId,
  (v) => {
    if (v) {
      chartRef.value?.clear();
      chartRef.value?.setOption(defaultOption);
      refreshRsltList();
    }
  }
);

const resize = useDebounceFn(() => {
  if (!chartRef.value) return;
  chartRef.value.resize();
}, 300);

const initChart = useDebounceFn(() => {
  if (!echartRef.value) return;
  chartRef.value = echarts.init(echartRef.value);
  chartRef.value?.setOption(defaultOption);
  refreshRsltList();
  useResizeObserver(echartRef.value, resize);
  useEventListener(window, "resize", resize);
}, 10);

useWs(WsMsgType.TASK_RESULT_UPDATE, (data: BuildTaskResult) => {
  if (props.task?.taskId === data.taskId) {
    // 更新结果
    refreshRsltList();
  }
});

onMounted(() => {
  initChart();
});
</script>

<template>
  <div class="detail-chart-wrap">
    <div class="tools">
      <span class="left">
        <h4>结果比较</h4>
        <el-button plain size="small" @click="() => (dialogVisible = true)"
          >查看表格</el-button
        >
      </span>
      <span>
        <el-radio-group
          v-model="activeType"
          @change="switchStatsType"
          :size="'small'"
          style="margin-right: 12px"
        >
          <el-radio-button
            v-for="item in timeStatsOption"
            :key="item.value"
            :value="item.value"
            >{{ item.label }}</el-radio-button
          >
        </el-radio-group>
        <el-radio-group
          v-model="chartType"
          @change="switchChartType"
          :size="'small'"
        >
          <el-radio-button
            v-for="item in chartTypeOption"
            :key="item.value"
            :value="item.value"
            >{{ item.label }}</el-radio-button
          >
        </el-radio-group>
      </span>
    </div>
    <div class="chart-wrap">
      <div ref="echartRef" class="chart-dom" />
    </div>
    <el-dialog draggable title="表格展示" v-model="dialogVisible">
      <el-table max-height="600px" stripe size="small" :data="dataSource">
        <el-table-column
          v-for="item in columns"
          :key="item.prop"
          :label="item.label"
          :prop="item.prop"
          :sortable="item.sortable"
          :min-width="item.minWidth"
        >
          <template #default="{ row }">
            {{ item.render ? item.render(row[item.prop]) : row[item.prop] }}
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <el-button
          type="primary"
          size="small"
          @click="() => (dialogVisible = false)"
          >确定</el-button
        >
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.detail-chart-wrap {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.tools {
  flex: 0 0 auto;
  width: 100%;
  margin-bottom: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  .left {
    display: flex;
    align-items: center;
    h4 {
      margin: 0;
      margin-right: 12px;
    }
  }
}
.chart-wrap {
  width: 100%;
  flex: 1;
  min-height: 250px;
  max-height: 500px;
  display: flex;
  flex-direction: column;
  .chart-dom {
    flex: 1;
    width: 100%;
    height: 100%;
  }
}
</style>
